<?php
/**
 * Created by sublime 3.
 * Auth: Inhere
 * Date: 14-10-28
 * Time: 10:35
 * Uesd: 主要功能是 hi
 */
namespace ulue\core\request;

use ulue\libs\helpers\DataHelper;
use ulue\core\abstracts\AbstractCore;

class Request extends AbstractCore
{
    /**
     * @var array
     */
    protected $inputs     = [];

    /**
     * use REST request
     * $_POST['_method']
     * @var string
     */
    public $methodParam = '_method';

    public function __construct()
    {
        $this->prepare();
    }

    protected function prepare()
    {
        \Debug::trace('i开始处理请求信息');

        if (!get_magic_quotes_gpc()) {
            $_POST      = DataHelper::slashes($_POST);    // 对 $_POST中的特殊字符前添加反斜线进行转义
            $_GET       = DataHelper::slashes($_GET);     // 对 $_GET 进行转义
            $_REQUEST   = DataHelper::slashes($_REQUEST); // 对 $_REQUEST 进行转义
            $_COOKIE    = DataHelper::slashes($_COOKIE);  // 对 $_COOKIE 进行转义
        }
    }

####################################### judge #######################################

    public function getIsAjax()
    {
        //return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && $_SERVER['HTTP_X_REQUESTED_WITH']==='XMLHttpRequest';

        return isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtoupper($_SERVER['HTTP_X_REQUESTED_WITH']) == 'XMLHTTPREQUEST';
    }

    /**
     * @param null $key
     * @return bool
     */
    public function getIsGet()
    {
        return $this->method === 'GET';
    }

    /**
     * @param null $key
     * @return bool
     */
    public function getIsPost()
    {
        return $this->method === 'POST';
    }

    /**
     * @form yii1
     * Returns whether this is a PUT request.
     * @return boolean whether this is a PUT request.
     */
    public function getIsPut()
    {
        return $this->method === 'PUT';
    }

    /**
     * @form yii1
     * Returns whether this is a DELETE request.
     * @return boolean whether this is a DELETE request.
     */
    public function getIsDelete()
    {
        return $this->method === 'DELETE';
    }

    /**
     * @form yii1
     * Returns whether this is a PATCH request.
     * @return boolean whether this is a PATCH request.
     */
    public function getIsPatch()
    {
        return $this->method === 'PATCH';
    }

    /**
     * @form yii1
     * Returns whether this is a HEAD request.
     * @return boolean whether this is a HEAD request.
     */
    public function getIsHead()
    {
        return $this->method === 'HEAD';
    }

    /**
     * @form yii1
     * Returns whether this is a PUT request which was tunneled through POST.
     * @return boolean whether this is a PUT request tunneled through POST.
     */
    protected function getIsPutByPost()
    {
        return $this->postMethod && !strcasecmp($this->postMethod,'PUT');
    }

    /**
     * @form yii1
     * Returns whether this is a PATCH request which was tunneled through POST.
     * @return boolean whether this is a PATCH request tunneled through POST.
     */
    protected function getIsPatchByPost()
    {
        return $this->postMethod && !strcasecmp($this->postMethod,'PATCH');
    }

    /**
     * Returns whether this is a DELETE request which was tunneled through POST.
     * @return boolean whether this is a DELETE request tunneled through POST.
     */
    protected function getIsDeleteByPost()
    {
        return $this->postMethod && !strcasecmp($this->postMethod,'DELETE');
    }

    /**
     * @form yii1
     * Returns whether this is an Adobe Flash or Adobe Flex request.
     * @return boolean whether this is an Adobe Flash or Adobe Flex request.
     */
    public function getIsFlash()
    {
        $userAgent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT']: null;

        return $userAgent && (stripos($userAgent,'Shockwave')!==false || stripos($userAgent,'Flash')!==false);
    }

///////////////////////////////////////////// Attributes /////////////////////////////////////////////

  /**
     * 响应头信息
     * @var array
     */
    private $_headers = null;

    public function getHeaders()
    {
        if ($this->_headers === null) {
            if (function_exists('getallheaders')) {
                $this->_headers = getallheaders();
            } elseif (function_exists('http_get_request_headers')) {
                $this->_headers = http_get_request_headers();
            } else {
                foreach ($_SERVER as $name => $value) {
                    if ( $name = $this->_nameConver($name)) {
                        $this->_headers[$name] = $value;
                    }
                }
            }
        }

        return $this->_headers;
    }

    public function setHeaders(array $headers)
    {
        $this->_headers = $headers;
    }

    // HTTP_X_TOKEN => xToken
    // HTTP_USER_AGENT => userAgent
    protected function _nameConver($string)
    {
        // if ( !strpos($string, '_') ) {
        //     return strtolower($string);
        // }

        if ( strpos($string,'HTTP_')!==false ) {
            $string    = substr($string, strlen('HTTP_'));
        } else {
            return false;
        }

        $arr_char  = explode('_', strtolower($string));
        $newString = array_shift($arr_char);

        foreach($arr_char as $val){
            $newString .= ucfirst($val);
        }

        return $newString;
    }

    public function getPathString()
    {
        # code...
    }


    private $_currentUrl;

    public function getCurrentUrl($value='')
    {
        # code...
    }

    private $_scriptFile;

    public function getScriptFile()
    {
        return $this->_scriptFile ? : $_SERVER['SCRIPT_FILENAME'];
    }

    public function setScriptFile($value)
    {
        $this->_scriptFile = $value;
    }

    private $_scriptName;

    private $_scriptUrl;

    public function getScriptUrl()
    {
        if ( !$this->_scriptUrl ) {
            $this->_scriptUrl = $_SERVER['SCRIPT_NAME'];
        }

        return $this->_scriptUrl;
    }

    private $_port;

    public function getPort()
    {
        if ($this->_port === null) {
            $this->_port = !$this->getIsSsl() && isset($_SERVER['SERVER_PORT']) ? (int) $_SERVER['SERVER_PORT'] : 80;
        }

        return $this->_port;
    }

    /**
     * @param integer $value port number.
     */
    public function setPort($value)
    {
        if ($value != $this->_port) {
            $this->_port    = (int) $value;
            $this->_rootUrl = null;
        }
    }

    private $_securePort;

    public function setSecurePort($value)
    {
        $this->_securePort = $value;
    }

    public function getSecurePort()
    {
        if (!$this->_securePort) {
            $this->_securePort = $this->getIsSsl() && isset($_SERVER['SERVER_PORT']) ? (int) $_SERVER['SERVER_PORT'] : 443;
        }

        return $this->_securePort;
    }

    private $_isSsl;

    /**
     * Determine if the protocol is HTTPS.
     * @return bool
     */
    public function getIsSsl()
    {
        if ( $this->_isSsl === null) {
            // Apache
            if ( isset($_SERVER['HTTPS']) === true ) {
                $this->_isSsl = ( $_SERVER['HTTPS'] === 'on' or $_SERVER['HTTPS'] === '1' );

            // IIS
            } elseif ( isset($_SERVER['SSL']) === true ) {
                $this->_isSsl = ( $_SERVER['SSL'] === 'on' );

            // Reverse proxy 反向代理
            } elseif ( isset($_SERVER['HTTP_X_FORWARDED_PROTO']) === true ) {
                $this->_isSsl = ( strtolower($_SERVER['HTTP_X_FORWARDED_PROTO']) === 'https' );

            // Reverse proxy
            } elseif ( isset($_SERVER['HTTP_X_FORWARDED_PORT']) === true ) {

                $this->_isSsl = ( $_SERVER['HTTP_X_FORWARDED_PORT'] === '443' );
            } elseif ( isset($_SERVER['SERVER_PORT']) === true ) {

                $this->_isSsl = $_SERVER['SERVER_PORT'] === '443';
            } else {
                $this->_isSsl = false;
            }
        }

        return $this->_isSsl;
    }

    protected function afterRequest()
    {}

    protected function filters()
    {
        return 'htmlspecialchars';
    }

    private $_method;

    public function getMethod()
    {
        if ( !$this->_method ) {
            if (isset($_POST[$this->methodParam])) {
                $this->_method = strtoupper($_POST[$this->methodParam]);
            } elseif (isset($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'])) {
                $this->_method = strtoupper($_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']);
            } else {
                $this->_method = isset($_SERVER['REQUEST_METHOD']) ? strtoupper($_SERVER['REQUEST_METHOD']) : 'GET';
            }
        }

        return $this->_method;
    }

    private $_rootUrl;

    /**
     * @from Yii2->request
     * @return string
     */
    public function getRootUrl()
    {
        if (!$this->_rootUrl) {
            $secure = $this->getIsSsl();
            $http = $secure ? 'https' : 'http';

            if (isset($_SERVER['HTTP_HOST'])) {
                $this->_rootUrl = $http . '://' . $_SERVER['HTTP_HOST'];
            } else {
                $this->_rootUrl = $http . '://' . $_SERVER['SERVER_NAME'];
                $port = $secure ? $this->getSecurePort() : $this->port;

                if (($port !== 80 && !$secure) || ($port !== 443 && $secure)) {
                    $this->_rootUrl .= ':' . $port;
                }
            }
        }

        return $this->_rootUrl;
    }

    private $_uri;

    /**
     * @return string
     */
    public function getUri()
    {
        return $this->getRequestUri();
    }

    /**
     * @return string
     */
    public function getUrl()
    {
        return $this->getRequestUri();
    }

    public function setUri($value)
    {
        $this->_uri = $value;
    }

    /**
     * @from Yii2->request
     *         $this->data['uri']         = rtrim( str_replace($this->rootUrl,'',$this->uri ),'?& ');
     * @return string
     */
    public function getRequestUri()
    {
        if (!$this->_uri) {
            if (isset($_SERVER['HTTP_X_REWRITE_URL'])) { // IIS
                $requestUri = $_SERVER['HTTP_X_REWRITE_URL'];
            } elseif (isset($_SERVER['REQUEST_URI'])) {
                $requestUri = $_SERVER['REQUEST_URI'];

                if ($requestUri !== '' && $requestUri[0] !== '/') {
                    $requestUri = preg_replace('/^(http|https):\/\/[^\/]+/i', '', $requestUri);
                }
            } elseif (isset($_SERVER['ORIG_PATH_INFO'])) { // IIS 5.0 CGI
                $requestUri = $_SERVER['ORIG_PATH_INFO'];

                if (!empty($_SERVER['QUERY_STRING'])) {
                    $requestUri .= '?' . $_SERVER['QUERY_STRING'];
                }
            } else {
                throw new \DRuntimeException('Unable to determine the request URI.');
            }

            $this->_uri = $requestUri;
        }

        return $this->_uri;
    }


    /**
     * @return string
     */
    public function getFullUrl()
    {
        return $this->getRootUrl() . $this->getRequestUri();
    }

    /**
     * == $this->queryString
     * @return string
     */
    // public function getQueryStr()
    // {
    //     return $this->queryString;
    // }



####################################### acquire  #######################################

    /**
     * 请求数据过滤,并获取值
     * USE:  getParam('get.id') || getParam('get.id',34)
     *       getParam('id')  || getParam('id',34)
     *       getParam('get.*')
     * @param null $name  method.name
     * @param string $default value
     * @param null $filter
     * @return mixed
     */
    public function getParam($name, $default=null, $filter=null)
    {
        $name   = trim($name, '. ');
        $method = 'request';

        if ( strpos($name, '.') ) {
            list($method, $name) = explode('.', $name,2);
        }

        switch ( strtoupper($method) ) {
            case 'POST':    $var    = &$_POST; break;
            case 'PUT':
                parse_str( file_get_contents('php://input'), $var);
                break;
            case 'REQUEST': $var    = &$_REQUEST; break;
            case 'SESSION': $var    = &$_SESSION; break;
            case 'SERVER' : $var    = &$_SERVER;  break;
            case 'COOKIE' : $var    = &$_COOKIE;  break;
            case 'GLOBALS': $var    = &$_GLOBALS; break;
            case 'GET':
            default:
                 $var    = &$_GET; break;
        }

        $filters = $this->getFilters($filter);
        $data    = $default;

        //getParam('get.*')
        if ( $name === '*' ) {
            $data   = RequestHelper::clearSpace($var);

        //getParam('get.id')
        } elseif ( isset($var[$name]) ) {
            $data   = RequestHelper::clearSpace($var[$name]);
        }

        foreach ($filters as $filter) {
            if ( is_callable($filter) ) {
                $data = is_array($data) ? array_map($filter, $data) : $filter($data);//参数过滤
            } else {
                $data = filter_var($data, is_int($filter) ? $filter : filter_id($filter));

                if (false === $data) {
                    return !is_null($default) ? $default: null;
                }
            }
        }

        return $data;
    }

    /**
     * @param string $key
     * @param null $default
     * @param null $filter
     * @return mixed
     */
    public function getSession($key='*', $default=null, $filter=null)
    {
        return $this->getParam('session.'.$key, $default, $filter);
    }

    private $_cookie;

    /**
     * @param string $key
     * @param null $default
     * @param null $filter
     * @return mixed
     */
    public function getCookie()
    {
        if (!$this->_cookie) {
            $this->_cookie = new Cookie;
        }

        return $this->_cookie;
    }

    private $_queryParams;

    public function getQueryParams()
    {
        if ( !$this->_queryParams ) {
            $this->_queryParams = $_GET;
        }

        return $this->_queryParams;
    }

    public function setQueryParams($values)
    {
        $this->_queryParams = (array)$values;
    }

    public function getQueryParam($name,$default=null)
    {
        $params = $this->getQueryParams();

        return isset($params[$name]) ? $params[$name] : $default;
    }

    // $_GET data
    /**
     * @param string $key
     * @param null $default
     * @param null $filter
     * @return mixed
     */
    public function get($key='*', $default=null, $filter=null)
    {
        return $this->getParam('get.'.$key, $default, $filter);
    }

    // $_POST data
    /**
     * @param string $key
     * @param null $default
     * @param null $filter
     * @return mixed
     */
    public function post($key='*', $default=null, $filter=null)
    {
        return $this->getParam('post.'.$key, $default, $filter);
    }

    /**
     * @param string $key
     * @param null $default
     * @param null $filter
     * @return mixed
     */
    public function put($key='*', $default=null, $filter=null)
    {
        if ( $this->getIsPutByPost() ) {
            return $this->getPost($key, $default, $filter);
        }

        if ( $this->getIsPut() ) {
            parse_str( file_get_contents('php://input'), $default);
        }

        return $default;
    }


    /**
     * @param $filter
     * @return array
     */
    protected function getFilters($filter)
    {
        if (!$filter) {
            return [];
        }

        if ( is_array($filter) ) {
            return $filter;
        }

        $filters = strpos($filter, ',') ? explode(',', $filter) : (array)$filter;

        return $filters;
    }

    /**
     * @from Yii2
     * @return mixed
     */
    public function getContentType()
    {
        if (isset($_SERVER["CONTENT_TYPE"])) {
            return $_SERVER["CONTENT_TYPE"];
        } elseif (isset($_SERVER["HTTP_CONTENT_TYPE"])) {
            //fix bug https://bugs.php.net/bug.php?id=66606
            return $_SERVER["HTTP_CONTENT_TYPE"];
        }

        return null;
    }

    public function getReferer()
    {
        return isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : null;
    }

    public function getClientAddr()
    {
        return isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : null;
    }

    public function getClientPort()
    {
        return isset($_SERVER['REMOTE_PORT']) ? $_SERVER['REMOTE_PORT'] : null;
    }
}